﻿#region Copyright

// // The contents of this file are subject to the Mozilla Public License
// // Version 1.1 (the "License"); you may not use this file except in compliance
// // with the License. You may obtain a copy of the License at
// //   
// // http://www.mozilla.org/MPL/
// //   
// // Software distributed under the License is distributed on an "AS IS"
// // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// // License for the specific language governing rights and limitations under 
// // the License.
// //   
// // The Initial Developer of the Original Code is Robert Smyth.
// // Portions created by Robert Smyth are Copyright (C) 2008-2013.
// //   
// // All Rights Reserved.

#endregion

using NoeticTools.NWorkflow.Exceptions;
using NoeticTools.NWorkflow.ProgressMonitoring;
using NoeticTools.NWorkflow.Steps;


namespace NoeticTools.NWorkflow
{
    public class ActivityRunner<T, TResult> : IActivityListener<TResult>
    {
        private readonly IActivity<TResult> _activity;
        private readonly IWorkflowRunner<T> _workflowRunner;
        private bool _running;
        private IStep _step;

        public ActivityRunner(IActivity<TResult> activity, IWorkflowRunner<T> workflowRunner)
        {
            _activity = activity;
            _workflowRunner = workflowRunner;
        }

        private object SyncRoot
        {
            get { return _activity.SyncRoot; }
        }

        public void OnProgress(IActivityProgress progress)
        {
            _workflowRunner.OnProgress(progress);
        }

        void IActivityListener<TResult>.OnCompleted(IActivity<TResult> activity)
        {
            lock (SyncRoot)
            {
                if (_running)
                {
                    _running = false;
                    if (ReferenceEquals(_workflowRunner.CurrentStep, _step))
                    {
                        _step.SetResult(_activity.End());
                    }
                }
            }
        }

        void IStepProgressListener.OnProgress(string stepName, IProgress progress)
        {
            _workflowRunner.OnProgress(stepName, progress);
        }

        public void Start()
        {
            lock (SyncRoot)
            {
                if (_running)
                {
                    throw new WorkflowException("Attempt to start an activity that is currently running.");
                }
                _running = true;

                _step = _workflowRunner.CurrentStep;
                _activity.Begin(this);
            }
        }

        public void Cancel()
        {
            lock (SyncRoot)
            {
                if (_running)
                {
                    _running = false;
                    _activity.Cancel();
                }
            }
        }

        public void OnEvent(object obj)
        {
            _activity.OnEvent(obj);
        }
    }
}